<?php

namespace App\Http\Services;


use AlibabaCloud\SDK\Dysmsapi\V20170525\Dysmsapi;
use AlibabaCloud\Tea\Exception\TeaUnableRetryError;
use App\Exceptions\MessageException;
use App\Models\MobileValidateCode;
use App\Models\SendSms;
use \Exception;
use AlibabaCloud\Tea\Exception\TeaError;
use AlibabaCloud\Tea\Utils\Utils;
use Darabonba\OpenApi\Models\Config;
use AlibabaCloud\SDK\Dysmsapi\V20170525\Models\SendSmsRequest;
use AlibabaCloud\Tea\Utils\Utils\RuntimeOptions;

class SMSService {

    public static function sendValidateCode($mobile)
    {
        //间隔60s时间验证
        $now = time();
        $existValidate = MobileValidateCode::query()
            ->where([
                ['mobile',$mobile],
                ['created_at','>=',date('Y-m-d H:i:s',$now - 60 )],
            ])
            ->first();

        if ($existValidate)
        {
            $passedTime = $now - strtotime($existValidate->created_at);
            $leftTime = 60 - $passedTime;
            throw new MessageException("请等待 $leftTime s 后,重新发送短信验证码.");
        }
        //发送短信验证码
        $code = rand(1001,9999);
        $res = self::sendSMS($mobile,$code);
        if (!empty($res['body']['Code']) && $res['body']['Code'] == 'OK'){

            MobileValidateCode::query()
                ->where([
                    ['mobile',$mobile],
                    ['created_at','<=',date('Y-m-d H:i:s',$now - 10 * 60) ],
                ])
                ->delete();

            MobileValidateCode::saveEntity([
                'mobile'     => $mobile,
                'code'       => $code,
                'created_at' => date('Y-m-d H:i:s'),
            ]);

            return true;

        }else{
            throw new MessageException("短信验证码发送失败,请稍后重试. " . $res['body']['Message'] ?? '');
        }
    }

    public static function verifyValidateCode($mobile,$code)
    {
        //验证
        $now = time();
        $existValidate = MobileValidateCode::query()
            ->where([
                ['mobile',$mobile],
                ['code',$code],
                ['created_at','>=', date('Y-m-d H:i:s',$now - 10 * 60) ],
            ])
            ->first();

        if ($existValidate)
        {
            return true;
        }

        return false;
    }

    public static function sendSMS($mobile , $code = '')
    {

        // 请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID 和 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
        // 工程代码泄露可能会导致 AccessKey 泄露，并威胁账号下所有资源的安全性。以下代码示例使用环境变量获取 AccessKey 的方式进行调用，仅供参考，建议使用更安全的 STS 方式，更多鉴权访问方式请参见：https://help.aliyun.com/document_detail/311677.html
        $client = self::createClient(getenv("ALI_YUN_ACCESS_KEY_ID"), getenv("ALI_YUN_ACCESS_KEY_SECRET"));

        $sendSmsRequest = new SendSmsRequest();

        $sendSmsRequest->phoneNumbers  = $mobile;
        $sendSmsRequest->signName      = '缘来网';
        $sendSmsRequest->templateCode  = 'SMS_295820047';
        $sendSmsRequest->templateParam = '{"code":"' . $code . '"}';

        //var_dump($sendSmsRequest->toMap());die;

        $runtime                 = new RuntimeOptions();
        $runtime->maxIdleConns   = 3;
        $runtime->connectTimeout = 10000;
        $runtime->readTimeout    = 10000;

        try {
            // 复制代码运行请自行打印 API 的返回值
            $result = $client->sendSmsWithOptions($sendSmsRequest, $runtime);

            $res = $result->toMap();

            $status = 'failed';
            if (array_key_exists('statusCode',$res) && $res['statusCode'] == 200 )
            {
                if (array_key_exists('Code',$res['body']) && $res['body']['Code'] == "OK" )
                {
                    $status = 'success';
                }
            }

            SendSms::saveEntity([
                'mobile'         => $mobile,
                'template_code'  => $sendSmsRequest->templateCode,
                'sign_name'      => $sendSmsRequest->signName,
                'template_param' => $sendSmsRequest->templateParam,
                'status'         => $status,
                'message'        => $res['body']['Message'] ?? '',
                'code'           => $res['body']['Code'] ?? '',
                'biz_id'         => $res['body']['BizId'] ?? '',
                'request_id'     => $res['body']['RequestId'] ?? '',
                'response'       => json_encode($res),
                'created_at'     => date('Y-m-d H:i:s'),
            ]);
//            ["statusCode"]=>
//              int(200)
//              ["body"]=>
//              array(3) {
//                ["Code"]     => "isv.SMS_TEMPLATE_ILLEGAL"
//                ["Message"]  =>  "该账号下找不到对应模板"
//                ["RequestId"]=> "32D0FAB7-FE05-5241-BACB-374FC5B23CFA"

            return $res;

        } catch (TeaUnableRetryError $e) {
            // 获取报错数据
            var_dump($e->getErrorInfo());
            // 获取报错信息
            var_dump($e->getMessage());
            // 获取最后一次报错的 Exception 实例
            var_dump($e->getLastException());
            // 获取最后一次请求的 Request 实例
            var_dump($e->getLastRequest());

            logger('sendSMS error : $e->getErrorInfo() = ' . $e->getErrorInfo() . "\n"
                . 'sendSMS error : $e->getMessage() = ' . $e->getMessage() . "\n"
                . 'sendSMS error : $e->getLastException() = ' . $e->getLastException() . "\n"
                . 'sendSMS error : $e->getErrorInfo() = ' . $e->getErrorInfo());

            return false;
        }
    }

    /**
     * 使用AK&SK初始化账号Client
     * @param string $accessKeyId
     * @param string $accessKeySecret
     * @return Dysmsapi Client
     */
    public static function createClient($accessKeyId, $accessKeySecret){
        $config = new Config([
            // 必填，您的 AccessKey ID
            "accessKeyId" => $accessKeyId,
            // 必填，您的 AccessKey Secret
            "accessKeySecret" => $accessKeySecret
        ]);
        // Endpoint 请参考 https://api.aliyun.com/product/Dysmsapi
        $config->endpoint = "dysmsapi.aliyuncs.com";
        return new Dysmsapi($config);
    }

    /**
     * @param string[] $args
     * @return void
     */
    public static function main($args){
        // 请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID 和 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
        // 工程代码泄露可能会导致 AccessKey 泄露，并威胁账号下所有资源的安全性。以下代码示例使用环境变量获取 AccessKey 的方式进行调用，仅供参考，建议使用更安全的 STS 方式，更多鉴权访问方式请参见：https://help.aliyun.com/document_detail/311677.html
        $client = self::createClient(getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"), getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"));
        $sendSmsRequest = new SendSmsRequest([]);
        $runtime = new RuntimeOptions([]);
        try {
            // 复制代码运行请自行打印 API 的返回值
            $client->sendSmsWithOptions($sendSmsRequest, $runtime);
        }
        catch (Exception $error) {
            if (!($error instanceof TeaError)) {
                $error = new TeaError([], $error->getMessage(), $error->getCode(), $error);
            }
            // 错误 message
            var_dump($error->message);
            // 诊断地址
            var_dump($error->data["Recommend"]);
            Utils::assertAsString($error->message);
        }
    }

}
